
#include <stdint.h>
#include <string.h> 

#include "xota.h"

#include "app_util.h"
//#include "..\util\util.h"

int xota_init_decode(    uint8_t * p_data,
                        uint16_t len,
                        ota_pb_create_command_t * p_init,
                        ota_value_length_t * p_ota_init_value
){
    if( len > OTA_PB_CREATE_COMMAND_SIZE){
        return 1; 
    }

    int index = 0;
    int res = OTA_EPB_SUCCESS; 
    while (index < len)
    {   
        uint8_t field_len = p_data[index + 0];
        uint8_t filed_type = p_data[index + 1];

        if( (field_len + index) > len)
        break;

        switch((PB_INIT_TYPE) filed_type)
        {
            case PB_INIT_SIGN:
            p_init->has_signed_command = 1;
            p_init->sign_command.signature_type = (ota_signature_type_t)p_data[index + 2];
            p_init->sign_command.signature.size = field_len - 2;
            if( field_len < 5 || field_len > 66 ){
                res = OTA_EPB_ERR_INVALID_LENGTH;
                break;
            }
            memcpy( p_init->sign_command.signature.bytes, p_data + index + 3, p_init->sign_command.signature.size);
            p_ota_init_value->p_value = p_data + index + field_len + 1; 
            p_ota_init_value->length = len - (index + field_len + 1);
            break;
            case PB_INIT_HASH:
            if( field_len < 6 || field_len > 34){
                res = OTA_EPB_ERR_INVALID_LENGTH; 
                break;
            }
            p_init->has_init = 1;
            p_init->init.has_hash = 1;
            p_init->init.hash.hash_type = (ota_hash_type_t)p_data[index + 2];
            p_init->init.hash.hash.size = field_len - 2; 
            memcpy( p_init->init.hash.hash.bytes, p_data + index + 3, p_init->init.hash.hash.size); 
            break;
            case PB_INIT_CRC32:
            if( field_len != 5){
                res = OTA_EPB_ERR_INVALID_LENGTH; 
                break;
            }
            p_init->has_init = 1;
            p_init->init.has_crc = 1;
            p_init->init.crc32 = uint32_decode( p_data + index + 2);
            break;
            case PB_INIT_OTA_TYPE:
            if( field_len != 5){
                res = OTA_EPB_ERR_INVALID_LENGTH; 
                break;
            }
            p_init->has_init = 1;
            p_init->init.has_type = 1;
            p_init->init.type = (ota_fw_type_t)uint32_decode( p_data + index + 2);
            break;
            case PB_INIT_APP_SIZE:
            if( field_len != 5){
                res = OTA_EPB_ERR_INVALID_LENGTH; 
                break;
            }
            p_init->has_init = 1;
            p_init->init.has_app_size = 1;
            p_init->init.app_size = uint32_decode( p_data + index + 2);
            break;
            case PB_INIT_FW_VER:
            if( field_len != 5){
                res = OTA_EPB_ERR_INVALID_LENGTH; 
                break;
            }
            p_init->has_init = 1; 
            p_init->init.has_fw_version = 1;
            p_init->init.fw_version = uint32_decode(p_data + index + 2);
            break;
            case PB_INIT_HW_VER:
            if( field_len != 5){
                res = OTA_EPB_ERR_INVALID_LENGTH; 
                break;
            }
            p_init->has_init = 1;
            p_init->init.has_hw_version = 1;
            p_init->init.hw_version = uint32_decode(p_data + index + 2); 
            break;

            case PB_INIT_APP_FWID:
            if( field_len != 5 )
            {
                res = OTA_EPB_ERR_INVALID_LENGTH; 
                break;
            }
            p_init->has_init = 1;
            p_init->init.has_app_fwid = 1;
            p_init->init.app_fwid = uint32_decode(p_data + index + 2);
            break;
            
            case PB_INIT_OPTION:
            p_init->init.has_option = 1;
            p_init->init.len_of_option = field_len - 1;
            p_init->init.option = p_data + index + 2;
            break;

            default:
            break;
        }

        index += field_len + 1; 
    }
    
    return res; 
}

int xota_write_decode( uint8_t * p_data, uint16_t len, ota_pb_write_command_t * p_write)
{
    if( p_data == NULL)
        return OTA_EPB_ERR_NULL;
    if( (len & 0x03) > 0)
        return OTA_EPB_ERR_DATA_SIZE_ERROR;
    if( len < OTA_PB_WRITE_COMMAND_MIN_SIZE || len > OTA_PB_WRITE_COMMAND_SIZE)
        return OTA_EPB_ERR_INVALID_LENGTH;
    
    p_write->offset = uint32_decode( p_data); 
    if( (p_write->offset & 0x03) > 0)
        return OTA_EPB_ERR_INVALID_ADDR;

    p_write->p_data = p_data + 4;
    p_write->size = len - 4; 
    
    return 0; 
}
